#pragma once

#include "Applications/Reflector/ReflectorSettingsAndUtils.h"
#include "Base/Types/StringID.h"
#include "Base/FileSystem/FileSystemPath.h"

//-------------------------------------------------------------------------

namespace EE::TypeSystem::Reflection
{
    typedef StringID HeaderID;
    typedef StringID ProjectID;

    //-------------------------------------------------------------------------

    struct HeaderInfo
    {
        inline static HeaderID GetHeaderID( FileSystem::Path const& headerFilePath )
        {
            String lowercasePath = headerFilePath.GetString();
            lowercasePath.make_lower();
            return StringID( lowercasePath.c_str() );
        }

    public:

        inline bool IsInToolsLayer() const
        {
            return Utils::IsFileUnderToolsProject( m_filePath );
        }

        inline FileSystem::Path const GetTypeInfoFilePath( FileSystem::Path const& projectDirectoryPath ) const
        {
            return Utils::GetAutogeneratedFilePath( projectDirectoryPath, m_filePath.GetFileNameWithoutExtension().c_str(), Settings::g_typeinfoFileSuffix, "h" );
        }

        inline FileSystem::Path const GetCodeGenFilePath( FileSystem::Path const& projectDirectoryPath ) const
        {
            return Utils::GetAutogeneratedFilePath( projectDirectoryPath, m_filePath.GetFileNameWithoutExtension().c_str(), Settings::g_codegenFileSuffix, "h" );
        }

    public:

        HeaderID                        m_ID;
        ProjectID                       m_projectID;
        FileSystem::Path                m_filePath;
        uint64_t                        m_timestamp = 0;
        uint64_t                        m_checksum = 0;
        TVector<String>                 m_fileContents;
    };

    //-------------------------------------------------------------------------

    struct ProjectInfo
    {
        inline static ProjectID GetProjectID( FileSystem::Path const& projectFilePath )
        {
            String lowercasePath = projectFilePath.GetString();
            lowercasePath.make_lower();
            return StringID( lowercasePath.c_str() );
        }

        inline bool IsBaseModule() const
        {
            return m_name == Settings::g_allowedProjectNames[0].m_pFullName;
        }

        inline HeaderInfo const& GetModuleHeaderInfo() const
        {
            EE_ASSERT( m_moduleHeaderID.IsValid() );
            for ( auto const& headerInfo : m_headerFiles )
            {
                if ( headerInfo.m_ID == m_moduleHeaderID )
                {
                    return headerInfo;
                }
            }

            EE_UNREACHABLE_CODE();
            static HeaderInfo const temp;
            return temp;
        }

        inline FileSystem::Path const GetAutogeneratedDirectoryPath() const
        {
            return Utils::GetAutogeneratedDirectoryNameForProject( m_path );
        }

        inline FileSystem::Path const GetTypeInfoFilePath() const
        {
            FileSystem::Path const directoryPath = GetAutogeneratedDirectoryPath();
            HeaderInfo const& moduleHeaderInfo = GetModuleHeaderInfo();
            return Utils::GetAutogeneratedFilePath( directoryPath, moduleHeaderInfo.m_filePath.GetFileNameWithoutExtension().c_str(), Settings::g_typeinfoFileSuffix, "cpp" );
        }

        inline FileSystem::Path const GetCodeGenFilePath() const
        {
            FileSystem::Path const directoryPath = GetAutogeneratedDirectoryPath();
            HeaderInfo const& moduleHeaderInfo = GetModuleHeaderInfo();
            return Utils::GetAutogeneratedFilePath( directoryPath, moduleHeaderInfo.m_filePath.GetFileNameWithoutExtension().c_str(), Settings::g_codegenFileSuffix, "cpp" );
        }

    public:

        ProjectID                       m_ID;
        String                          m_name;
        String                          m_shortName;
        FileSystem::Path                m_path;
        String                          m_exportMacro;
        HeaderID                        m_moduleHeaderID;
        uint32_t                        m_dependencyCount = 0;
        TVector<HeaderInfo>             m_headerFiles;
        TVector<ProjectID>              m_dependencies;
        mutable String                  m_moduleClassName;
        bool                            m_includeInAutogenerateModuleRegistrationList = true;
        bool                            m_isToolsModule = false;
    };

    //-------------------------------------------------------------------------

    struct SolutionInfo
    {
        FileSystem::Path                m_path;
        TVector<ProjectInfo>            m_projects;
        TVector<FileSystem::Path>       m_excludedProjects;
    };
}